package com.numericalmethod.algoquant.model.ralph2009.draft;

import java.util.Arrays;

import org.apache.commons.math3.util.ArithmeticUtils;

public abstract class AbstractFunction {

	private static final double DELTA = 0.00000001;
	
	public abstract int getAxisCount();
	
	public abstract double compute(double[] input);
	
	/**
	 * Compute n-th order partial derivatives of this function
	 * 
	 * @param input The coordinate that we want to compute the partial derivative
	 * @param axis The axis for the derivative.
	 * @param order Differentiate how many times.
	 * @return The numerical value of the partial derivative.
	 */
	public double getPartialDerviative(double[] input, int axis, int order) {
		
		double[] inputCopy = Arrays.copyOf(input, input.length);
		
		// center difference
		double original = inputCopy[axis];

		double centerDifference = 0.0;
		
		double nFactorial = ArithmeticUtils.factorialDouble(order); 
		for (int i=0;i<=order;i++) {
			// ncr
			double iFactorial = ArithmeticUtils.factorialDouble(i);
			double nMinusIFactorial = ArithmeticUtils.factorialDouble(order-i);
			double nci=nFactorial / (iFactorial * nMinusIFactorial);
			// invoke the function
			inputCopy[axis] = original + (((double) order)/2.0 - (double) i)*DELTA;
			double f=compute(inputCopy);
			// sum up center difference
			centerDifference += (Math.pow(-1.0, i) * nci * f);  
		}
		
		return centerDifference / Math.pow(DELTA, order);
	}
	
}
